/**
 * Copyright &copy; 2013-2015 山东易科德软件有限公司   All rights reserved.
 */
package cn.net.ecode.modules.file.web;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.Thumbnails.Builder;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import cn.net.ecode.common.config.Global;
import cn.net.ecode.common.mapper.JsonMapper;
import cn.net.ecode.common.utils.ByteSizeUtils;
import cn.net.ecode.common.utils.DateUtils;
import cn.net.ecode.common.utils.FileUtils;
import cn.net.ecode.common.utils.StringUtils;
import cn.net.ecode.common.web.BaseController;
import cn.net.ecode.modules.file.entity.FileEntity;
import cn.net.ecode.modules.file.entity.FileParms;
import cn.net.ecode.modules.file.entity.FileUser;
import cn.net.ecode.modules.file.entity.FileUserBiz;
import cn.net.ecode.modules.file.service.FileService;
import cn.net.ecode.modules.sys.entity.User;
import cn.net.ecode.modules.sys.utils.UserUtils;

import com.google.common.collect.Maps;

/**
 * 文件管理Controller
 * @author jiangwenchao、ThinkGem
 * @version 2015-6-11
 */
@Controller
@RequestMapping(value = "${adminPath}/file")
public class FileController extends BaseController {

	@Autowired
	private FileService fileService;

	/**
	 * 上传文件
	 * @param uploadSave
	 * @return
	 */
	@RequiresPermissions("user")
	@ResponseBody
	@RequestMapping(value = "upload")
	public String upload(FileParms fileParms, HttpServletRequest request, HttpServletResponse response) {
		long startTime = System.currentTimeMillis(); // 获取开始时间
		Map<String, String> resultMap = Maps.newHashMap();
		String result = Global.FALSE, code = "server", message = StringUtils.EMPTY;
		// 创建一个通用的多部分解析器，并判断 request 是否有文件上传，即多部分请求
		CommonsMultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
		if (resolver.isMultipart(request)) {
			// 上传文件类型（image、media、file）
			String uploadType = fileParms.getUploadType();
			// 允许上传文件后缀限制
			String suffixs = StringUtils.EMPTY;
			if (FileParms.FILE_TYPE_IMAGE.equals(uploadType)) {
				suffixs = fileParms.getImageAllowSuffixs();
			} else if (FileParms.FILE_TYPE_MEDIA.equals(uploadType)) {
				suffixs = fileParms.getMediaAllowSuffixs();
			} else if (FileParms.FILE_TYPE_FILE.equals(uploadType)) {
				suffixs = fileParms.getFileAllowSuffixs();
			} else {
				suffixs = fileParms.getAllowSuffixs();
			}
			String[] allowSuffixs = StringUtils.split(suffixs, ",");
			// 强制转换为SpringMVC的文件上传请求对象
			MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
			// 获取request中上传文件的所有文件名，并遍历
			Iterator<String> iter = multiRequest.getFileNames();
			while (iter.hasNext()) {
				// 取得上传文件
				MultipartFile file = multiRequest.getFile(iter.next());
				FileEntity fileEntity = new FileEntity();
				String fileName = StringUtils.EMPTY;
				String fileId = StringUtils.EMPTY;
				boolean secondUpload = false; // 是否秒传
				if (file != null && !file.isEmpty() && file.getOriginalFilename() != null) {
					// 取得当前上传文件的文件名称
					fileName = file.getOriginalFilename().trim();
					String fileMd5 = fileParms.getFileMd5();
					if (StringUtils.isNotBlank(fileMd5)) {
						fileEntity.setFileMd5(fileMd5);
						List<FileEntity> fileEntityList = fileService.getFileList(fileEntity);
						if (fileEntityList.size() > 0) {
							fileEntity = fileEntityList.get(0);
						}
						// 判断文件之前是否已经上传过(不代表文件还存在)
						if (StringUtils.isNotBlank(fileEntity.getFileId())) {
							fileId = fileEntity.getFileId();
							// 判断文件是否存在，如果文件还存在则定义为秒传，否则再传一次
							String path = fileParms.getAbsolutePathByRel(fileEntity.getFilePath()) + fileId + fileEntity.getFileSuffix();
							java.io.File localFile = new java.io.File(path);
							if (localFile.exists()) {
								secondUpload = true;
							}
						}
					} else {
						message = "文件错误,请重试.";
						break;
					}
					// 得到文件大小
					long fileSize = file.getSize();
					// 上传文件夹大小限制
					int maxFileSize = fileParms.getMaxFileSize();
					// 得到文件后缀
					String fileSuffix = "." + FileUtils.getFileExtension(fileName);
					// 验证文件是否合法,包括：验证文件大小、验证文件后缀
					if (fileSize <= maxFileSize && ArrayUtils.contains(allowSuffixs, fileSuffix)) {
						try {
							// 如果没有上传过
							if (!secondUpload) {
								// 插入或更新文件表信息
								fileEntity.setFileSize(fileSize);
								fileEntity.setFilePath(fileParms.getRelativePath());
								fileEntity.setFileMd5(fileMd5);
								fileEntity.setFileSuffix(fileSuffix);
								fileEntity.setFileType(file.getContentType());
								fileService.saveFile(fileEntity);
								fileId = fileEntity.getFileId();
								// 定义上传路径，上传文件到服务器
								String path = fileParms.getAbsolutePath() + fileId + fileSuffix;
								java.io.File localFile = new java.io.File(path);
								if (!localFile.exists()) { // 判断文件夹是否存在
									localFile.mkdirs(); // 不存在则创建
								}
								file.transferTo(localFile);
								// 如果设置了图片最大宽高，则按指定宽高压缩图片
								if (FileParms.FILE_TYPE_IMAGE.equals(uploadType)) {
									int maxWidth = -1, maxHeight = -1;
									if (StringUtils.toInteger(fileParms.getImageMaxWidth()) > 0){
										maxWidth = fileParms.getImageMaxWidth();
									}
									if (StringUtils.toInteger(fileParms.getImageMaxHeight()) > 0){
										maxHeight = fileParms.getImageMaxHeight();
									}
									if (maxWidth != -1 || maxHeight != -1){
										Builder<File> bilder = Thumbnails.of(localFile);
										BufferedImage bufferedImage = ImageIO.read(localFile);
										if (maxWidth != -1){
											if (bufferedImage.getWidth() <= fileParms.getImageMaxWidth()){
												bilder.width(bufferedImage.getWidth());
											}else{
												bilder.width(maxWidth);
											}
										}
										if (maxHeight != -1){
											if (bufferedImage.getHeight() <= fileParms.getImageMaxHeight()){
												bilder.height(bufferedImage.getHeight());
											}else{
												bilder.height(maxHeight);
											}
										}
										bilder.toFile(localFile);
									}
								}
							}
							
							// 保存文件和用户关系文件数据
							FileUser fileUser = new FileUser(fileEntity);
							fileUser.setFileName(fileName);
							fileUser.setFileCategory(uploadType);
							fileUser.setCreateBy(fileUser.getCurrentUser());
							fileUser.setStatus(FileUser.STATUS_NORMAL);
							// 验证是否已经存储了相同的文件，如果存在则只刷新更新状态
							List<FileUser> fileUserList = fileService.findFileUserList(fileUser);
							if (fileUserList.size() > 0){
								fileUser = fileUserList.get(0);
							}
							fileService.saveFileUser(fileUser);
							
							// 设置返回到页面的信息
							result = Global.TRUE;
							resultMap.put("fileId", fileId);
							resultMap.put("fileUserId", fileUser.getFileUserId());
							resultMap.put("fileDownloadPath", fileEntity.getFileDownloadPath());
							resultMap.put("fileName", fileUser.getFileName());
							if (secondUpload) {
								message = "秒传成功";
							} else {
								message = "上传成功,用时" + DateUtils.formatDateTime(System.currentTimeMillis() - startTime);
							}
						} catch (Exception e) {
							message = "上传错误!";
							break;
						}
					} else {
						if (fileSize > maxFileSize) {
							message = "大小不能超过" + ByteSizeUtils.byteSize(maxFileSize);
							code = "exceed_size";
						}
						if (!ArrayUtils.contains(allowSuffixs, fileSuffix)) {
							if (FileParms.FILE_TYPE_IMAGE.equals(uploadType)) {
								message = "只能上传图片（" + suffixs + "）";
							} else if (FileParms.FILE_TYPE_MEDIA.equals(uploadType)) {
								message = "只能上传视频（" + suffixs + "）";
							} else if (FileParms.FILE_TYPE_FILE.equals(uploadType)) {
								message = "只能上传文档（" + suffixs + "）";
							} else {
								message = "格式不正确（" + suffixs + "）";
							}
							code = "not_allow_type";
						}
						break;
					}
				} else {
					message = "没有所需的上传文件!";
					break;
				}
			}
		} else {
			message = "没有所需的上传文件!";
		}
		resultMap.put("result", result);
		resultMap.put("code", code);
		resultMap.put("message", message);
		return JsonMapper.toJsonString(resultMap);
	}

	/**
	 * 删除文件
	 * @param fileParms
	 * @return
	 */
	@RequiresPermissions("user")
	@ResponseBody
	@RequestMapping(value = "delFile")
	public String delFile(FileParms fileParms, RedirectAttributes redirectAttributes) {
		String fileUserId = fileParms.getFileUserId();
		String fileId = fileParms.getFileId();
		if (StringUtils.isBlank(fileUserId) || StringUtils.isBlank(fileId)) {
			return renderResult(Global.FALSE, "参数异常，文件不存在！");
		} else {
			// 查询该文件是否有业务关系。
			// 如果没有则“物理删除文件”和“用户和文件的关系”数据库记录 （本人创建）
			// 有，则仅仅逻辑删除 （业务关系表。用户上传关系表）
			User user = UserUtils.getUser();
			if (StringUtils.isBlank(user.getId())) {
				return renderResult(Global.FALSE, "请先登录！");
			}
			FileUser fileUser = fileService.getFileUser(fileUserId);
			// FileUserBiz fileUserBiz=new FileUserBiz(fileUser);
			if (!(fileUser != null && fileUser.getCreateByCode().equals(user.getUserCode()))) {
				return renderResult(Global.FALSE, "只能删除本人上传的文件！");
			}
			FileEntity fileEntity = fileService.getFile(new FileEntity(fileId));
			// 根据文件ID查询关联业务
			List<FileUserBiz> fubList = fileService.findFileUserBizListByFileEntity(fileEntity);
			// 查看该文件是否映射多条上传关系 ，如果仅仅一条 且 fileUserId 是当前 用户 上传的则可以删除
			List<FileUser> fuList = fileService.findFileUserListByFileEntity(fileUser);
			// 没有业务关系
			if (fubList == null || fubList.size() <= 0) {
				if (fuList != null && fuList.size() == 1) {
					FileUser fuTemp = fuList.get(0);
					if (fuTemp.getFileUserId().equals(fileUserId)) {
						// 真实删除数据记录和真实文件
						fileService.deleteFile(fileEntity);
						fileService.deleteFileUser(fileUser);
						String fileName = fileParms.getAbsolutePathByRel(fileEntity.getFilePath()) + fileId + fileEntity.getFileSuffix();
						FileUtils.deleteFile(fileName);
					}
				} else if (fuList != null && fuList.size() > 1) { //
					// 多条关系记录 仅仅逻辑删除 fileUser 表
					fileService.deleteFileUser(fileUser);
				} else {
					return renderResult(Global.FALSE, "数据异常！");
				}
			}
			// 存在业务关系 ，仅仅 逻辑删除 业务关系表
			else {

			}
		}
		return renderResult(Global.TRUE, "删除文件成功！");
	}
	
	/** 
	 * 删除业务关系
	 * @param fileUserBiz
	 * @return String  
	 */
	@RequiresPermissions("user")
	@ResponseBody
	@RequestMapping(value = "delFileBiz")
	public String delFileBiz(FileUserBiz fileUserBiz) {
		fileService.delFileUserBiz(fileUserBiz);
		return renderResult(Global.TRUE, "删除文件成功！");
	}

	/**
	 * 下载文件
	 * @param fileUserId
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	@RequiresPermissions("user")
	@RequestMapping(value = {"/download/{fileUserId}", "/download/{fileUserId}.html"}, method = RequestMethod.GET)
	public void download(@PathVariable("fileUserId") String fileUserId, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String error = "";
		if (StringUtils.isNotBlank(fileUserId)) {
			// 下载文件
			FileParms fileParms = new FileParms();
			FileUser fileUser = fileService.getFileUser(fileUserId);
			if (fileUser != null && fileUser.getFileEntity() != null && fileUser.getFileEntity().getFileMd5() != null) {
				FileEntity fileEntity = fileUser.getFileEntity();
				File file = new File(fileParms.getAbsolutePathByRel(fileEntity.getFilePath()) + fileEntity.getFileId() + fileEntity.getFileSuffix());
				logger.debug("Download file: {}  Range: {}", file, request.getHeader("Range"));
				error = FileUtils.downFile(file, request, response, fileUser.getFileName());
			} else {
				error = "文件不存在";
			}
		} else {
			error = "参数异常";
		}
		if (error != null) {
			request.setAttribute("message", error);
			request.getRequestDispatcher("/WEB-INF/views/error/404.jsp").forward(request, response);
		}
	}
	
	/** 
	 * 获取业务附件列表数据
	 * @param fileUserBiz
	 * @return String  
	 */
	@RequiresPermissions("user")
	@ResponseBody
	@RequestMapping(value = "fileList")
	public String fileList(FileUserBiz fileUserBiz) {
		List<FileUserBiz> list = fileService.findListByBiz(fileUserBiz);
		if(list != null && list.size()>0){
			return JsonMapper.toJsonString(list);
		}
		return renderResult(Global.FALSE, "没有附件");
	}

}